﻿using System;
using System.Text;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using SedionFormDesigner.Infrastructure;

namespace SedionFormDesigner.Service
{
    public class SedionEventBindingService : IEventBindingService
    {
        private Hashtable eventProperties;
        private IServiceProvider provider;
        internal IServiceProvider Provider { get { return provider; } }

        public SedionEventBindingService(IServiceProvider provider)
        {
            if (provider == null)
                throw new ArgumentNullException("provider");

            this.provider = provider;
        }

        #region IEventBindingService 成员

        string IEventBindingService.CreateUniqueMethodName(IComponent component, EventDescriptor e)
        {
            if (component == null)
                throw new ArgumentNullException("component");
            if (e == null)
                throw new ArgumentNullException("e");

            return CreateUniqueMethodName(component, e);
        }

        System.Collections.ICollection IEventBindingService.GetCompatibleMethods(EventDescriptor e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            return GetCompatibleMethods(e);
        }

        /// <summary>
        ///  获得属性事件相关信息类
        /// </summary>
        EventDescriptor IEventBindingService.GetEvent(PropertyDescriptor property)
        {
            if (property is EventPropertyDescriptor)
                return ((EventPropertyDescriptor)property).Event;
            else
                return null;
        }

        /// <summary>
        ///  根据事件集合获得事件属性集合
        /// </summary>
        PropertyDescriptorCollection IEventBindingService.GetEventProperties(EventDescriptorCollection events)
        {
            if (events == null)
                throw new ArgumentNullException("events");

            PropertyDescriptor[] props = new PropertyDescriptor[events.Count];

            // 为了性能缓存属性描述
            if (eventProperties == null)
                eventProperties = new Hashtable();

            // 生成hashcode如果不在键值对重,则生成数据并存储到键值对中
            for (int i = 0; i < events.Count; i++)
            {
                Object eventHashCode = GetEventDescriptorHashCode(events[i]);

                props[i] = (PropertyDescriptor)eventProperties[eventHashCode];

                if (props[i] == null)
                {
                    props[i] = new EventPropertyDescriptor(events[i], this);
                    eventProperties[eventHashCode] = props[i];
                }
            }

            return new PropertyDescriptorCollection(props);
        }

        /// <summary>
        ///  根据事件获得事件属性
        /// </summary>
        PropertyDescriptor IEventBindingService.GetEventProperty(EventDescriptor e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            if (eventProperties == null)
                eventProperties = new Hashtable();

            // 生成hashcode如果不在键值对重,则生成数据并存储到键值对中
            Object eventHashCode = GetEventDescriptorHashCode(e);
            PropertyDescriptor prop = (PropertyDescriptor)eventProperties[eventHashCode];
            if (prop == null)
            {
                prop = new EventPropertyDescriptor(e, this);
                eventProperties[eventHashCode] = prop;
            }

            return prop;
        }

        bool IEventBindingService.ShowCode(IComponent component, EventDescriptor e)
        {
            if (component == null)
                throw new ArgumentNullException("component");

            if (e == null)
                throw new ArgumentNullException("e");

            PropertyDescriptor prop = ((IEventBindingService)this).GetEventProperty(e);
            String methodName = (String)prop.GetValue(component);
            if (methodName == null)
                return false;

            return ShowCode(component, e, methodName);
        }

        bool IEventBindingService.ShowCode(int lineNumber)
        {
            return ShowCode(lineNumber);
        }

        bool IEventBindingService.ShowCode()
        {
            return ShowCode();
        }

        #endregion

        protected String CreateUniqueMethodName(IComponent component, EventDescriptor e)
        {
            String name = component.ToString().Split(new Char[] { ' ' })[0];
            return String.Concat("handler_", name, "_", e.Name);
        }

        protected ICollection GetCompatibleMethods(EventDescriptor e)
        {
            return new String[] { };
        }

        private String GetEventDescriptorHashCode(EventDescriptor eventDesc)
        {
            StringBuilder builder = new StringBuilder(eventDesc.Name);
            builder.Append(eventDesc.EventType.GetHashCode().ToString());

            foreach (Attribute attr in eventDesc.Attributes)
            {
                builder.Append(attr.GetHashCode().ToString());
            }

            return builder.ToString();
        }

        protected Boolean ShowCode() { return false; }

        protected Boolean ShowCode(Int32 lineNumber) { return false; }

        protected Boolean ShowCode(Object component, EventDescriptor e, String methodName) { return false; }

        /// <summary>
        ///  释放方法资源
        /// </summary>
        internal virtual void FreeMethod(Object component, EventDescriptor e, String methodName)
        {
            // 没有为当前句柄签署方法
            // 所以无需移除
        }

        /// <summary>
        ///  添加方法到事件句柄
        /// </summary>
        internal virtual void UseMethod(Object component, EventDescriptor e, String methodName)
        {
            // 不添加方法签名
        }

        /// <summary>
        ///  验证方法名是否合法
        /// </summary>
        internal virtual void ValidateMethodName(String methodName)
        {
            // 不支持方法名称的验证
        }
    }
}
